from pg_database import *
from flask import Flask, g
from flask import abort
from flask import request
from flask import Blueprint, current_app
import json
import time
from utils import get_real_addr
from sqlalchemy import desc, distinct

LOG = config.getlogger()

info = Blueprint('info', __name__)


def auth(addr, signature):
    query_result = pg_db_session.query(commonheartbeatview).filter(
        commonheartbeatview.ip == addr).filter(
            commonheartbeatview.source == 'Mondo').order_by(
                desc(commonheartbeatview.contact))
    if query_result.count() == 0 or signature is None:
        LOG.info('auth no signature registed: %s %s' % (addr, signature))
        return False
    if query_result.first().state != signature:
        LOG.info('auth signature error: %s %s [%s]' %
                 (addr, signature, query_result.first().state))
        return False
    else:
        return True


@info.route('/oldpass', methods=['POST'])
def query_old():
    try:
        addr = get_real_addr()
        signature = request.form.get('signature')
        LOG.error('query old pass from %s %s' % (addr, signature))
        if not auth(addr, signature):
            abort(404)
        query_result = pg_db_session.query(passwdlist).filter(
            passwdlist.ip == addr).order_by(desc(passwdlist.contact))
        if query_result.count() == 0:
            return 'N/A'  #default pass
        else:
            return query_result.first().password
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()


@info.route('/passwd', methods=['POST'])
def update_new():
    try:
        new = request.form.get('altered')
        addr = get_real_addr()
        signature = request.form.get('signature')
        if new is None or not auth(addr, signature):
            abort(404)
        pg_db_session.add(passwdlist(ip=addr, password=new))
        pg_db_session.commit()
        return 'ok'
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()


@info.route('/report/<ip>/<date_param>', methods=['POST'])
def do_report(ip, date_param):
    try:
        int(date_param)
        tbclz = create_if_not_exist('report_' + date_param)
        rpt_data = json.loads(request.form.get('data', '[]'))
        query_result = pg_db_session.query(tbclz).filter(tbclz.ip == ip)
        if query_result.count() > 0:
            for item in query_result.all():
                pg_db_session.delete(item)
        for data in rpt_data:
            value = data['value']
            if type(value) == float:
                item = tbclz(
                    ip=ip,
                    metric=rpt_data['metric'],
                    submetric=rpt_data['submetric'],
                    path=rpt_data['path'],
                    flag=rpt_data['flag'],
                    value=value,
                    contact=int(time.time()))
            else:
                item = tbclz(
                    ip=ip,
                    metric=rpt_data['metric'],
                    submetric=rpt_data['submetric'],
                    path=rpt_data['path'],
                    flag=rpt_data['flag'],
                    value=value,
                    contact=int(time.time()))
            pg_db_session.add(item)
        pg_db_session.commit()
        return 'ok'
    except TypeError:
        abort(500)
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()


@info.route('/report/<ip>/<date_param>', methods=['GET'])
@info.route('/report/<ip>/<date_param>/<metric>', methods=['GET'])
@info.route('/report/<ip>/<date_param>/<metric>/<submetric>', methods=['GET'])
def show_report(ip, date_param, metric=None, submetric=None):
    try:
        tbclz = create_if_not_exist('report_' + date_param)
        query_result = pg_db_session.query(tbclz).filter(tbclz.ip == ip)
        if metric:
            query_result = query_result.filter(tbclz.metric == metric)
        if submetric:
            query_result = query_result.filter(tbclz.submetric == submetric)
        ret = {}
        for item in query_result.all():
            data = item.strvalue if item.value is None else item.value
            if item.metric not in ret:
                ret[item.metric] = {}
            if item.path == "":
                ret[item.metric][item.submetric] = data
            else:
                if item.submetric not in ret[item.metric]:
                    ret[item.metric][item.submetric] = {}
                ret[item.metric][item.submetric][item.path] = data
        return json.dumps(ret)
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()


@info.route('/hardware/<ip>', methods=['GET'])
def info_status(ip=None):
    try:
        b = request.args.get('showall') is not None
        if ip == None:
            ip = get_real_addr()
        ret = {}
        for tb in [hardwaremetric, hardwareinfo]:
            query_result = pg_db_session.query(tb).filter(
                tb.ip == ip).order_by(tb.contact)
            for item in query_result.all():
                k = item.name
                v = item.value
                if b:
                    if k not in ret:
                        ret[k] = {}
                    ret[k][str(item.contact)] = v
                else:
                    ret[k] = v
        return json.dumps(ret)
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()


def update(session, addr, k, v):
    tbname = None
    if type(v) == type(0):
        tbname = hardwaremetric
    else:
        tbname = hardwareinfo
    if tbname is not None:
        query_result = session.query(tbname).filter(tbname.ip == addr).filter(
            tbname.name == k).order_by(tbname.contact)
        cnt = query_result.count()
        for item in query_result.all():
            if cnt < 2:
                break
            session.delete(item)
            cnt -= 1
        session.add(tbname(ip=addr, name=k, value=v))


@info.route('/hardware', methods=['POST'])
@info.route('/hardware/<ip>', methods=['POST'])
def update_info(ip=None):
    try:
        addr = get_real_addr()
        ret = request.form.get('info')
        d = json.loads(ret)
        for k, v in d.items():
            update(pg_db_session, addr, k, v)
        pg_db_session.commit()
        LOG.info('recieve sysinfo data from %s' % addr)
        return 'ok'
    except Exception, ex:
        LOG.error(ex)
        abort(500)
    finally:
        pg_db_session.close()
